package com.example.tutorial.java.concurrent;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * CountDownLatch 同步工具类，允许一个或多个线程一直等待，直到其它线程的操作执行完后再执行
 * 实现原理：
 * 通过计数器实现，计数器的初始值为线程数量，每当一个线程完成了自己的任务后，计数器值减1；
 * 当计数器值为0时，表示所有线程已完成任务，然后在闭锁上等待的线程就可以恢复执行任务
 *
 * @author cph
 * @version 1.0
 * @date 2019/1/6
 */
public class CountDownLatchTest {
    public static void main(String[] args) {

        ThreadPoolExecutor executor =
                new ThreadPoolExecutor(4, 4, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
        executor.allowCoreThreadTimeOut(true);
        final CountDownLatch latch = new CountDownLatch(2);
        List<Future<Integer>> list = new ArrayList<>();

        for (int i = 0; i < 2; i++) {
            executor.execute(new SubThread(latch));
            Future<Integer> submit = executor.submit(new SubThreadPlus(i, latch));
            list.add(submit);
        }

        try {
            System.out.println("等待" + latch.getCount() + "个子线程执行...");
            // 子线程启动完毕后立即调用，主线程在闭锁上等待
            latch.await();
            System.out.println("子线程执行完毕");
            System.out.println("继续执行主线程");
            list.forEach(t -> {
                try {
                    System.out.println(t.get());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            });
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    static class SubThread implements Runnable {

        private CountDownLatch latch;

        public SubThread(CountDownLatch latch) {
            this.latch = latch;
        }

        @Override
        public void run() {
            try {
                System.out.println("子线程" + Thread.currentThread().getName() + "正在执行");
                Thread.sleep(2000L);
                System.out.println("子线程" + Thread.currentThread().getName() + "执行完毕");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                if (latch != null) {
                    // 子线程执行结束时调用，通知主线程
                    latch.countDown();
                }
            }
        }
    }

    static class SubThreadPlus implements Callable<Integer> {

        private Integer cnt;
        private CountDownLatch latch;

        public SubThreadPlus(Integer cnt, CountDownLatch latch) {
            this.cnt = cnt;
            this.latch = latch;
        }

        @Override
        public Integer call() throws Exception {
            System.out.println(Thread.currentThread().getName() + ", " + latch.getCount());
            latch.countDown();
            return cnt + 100;
        }
    }

}
